home *** CD-ROM | disk | FTP | other *** search
- Subject: v08i073: Bidirectional getty/login for SystemV, Part02/02
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: mit-eddie!cdx39!jc (John Chambers)
- Mod.sources: Volume 8, Issue 73
- Archive-name: uutty/Part02
-
- [ Sorry for the mixed-mode address on the previous article... --r$ ]
-
- : This is a shar archive. Extract with sh, not csh
- echo file: lastfield.c
- cat > lastfield.c << '\!Funky\!Stuff\!'
- /*
- ** Find the last field of a string.
- */
- char *
- lastfield(p,c)
- char *p; /* Null-terminated string to scan */
- int c; /* Separator char, usually '/' */
- { char *r;
-
- r = p;
- while (*p) /* Find the last field of the name */
- if (*p++ == c)
- r = p;
- return r;
- }
- \!Funky\!Stuff\!
- echo file: lockname.c
- cat > lockname.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Build name for a lockfile.
- */
- lockname()
- { char *dp, *lp, *rp;
-
- D5("lockname(\"%s\")",device);
- devfld = dp = lastfield(device,'/');
- D4("devfld=\"%s\" device=\"%s\"",devfld,device);
- lp = lockfile; /* Place to build lockfile name */
- rp = lockroot; /* Place to build lockfile name */
- while (*rp) *lp++ = *rp++; /* Copy root to lockname */
- while (*dp) *lp++ = *dp++; /* Append the device name */
- *lp = 0;
- D4("lockname:lockfile=\"%s\"",lockfile);
- }
- \!Funky\!Stuff\!
- echo file: lockup.c
- cat > lockup.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** The lockfile exists; hang until it disappears.
- */
- lockup()
- { int n;
-
- n = 0;
- do {
- if ((n==0 && debug>=2) || debug>=3)
- P("%s Lockfile \"%s\" exists.",getime(),lockfile);
- if (lsleep > 0)
- sleep(lsleep);
- ++n;
- }
- while (stat(lockfile,&status) >= 0);
- D3("locked: Lockfile \"%s\" freed.",lockfile);
- if (debug>=2)
- P("%s Lockfile \"%s\" gone.",getime(),lockfile);
- return n;
- }
- \!Funky\!Stuff\!
- echo file: lockwait.c
- cat > lockwait.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Wait on a lockfile.
- */
- lockwait()
- { unsigned n;
-
- D5("lockwait()");
- if (lockfile[0] == 0) lockname();
- D4("lockwait:lockfile=\"%s\"",lockfile);
- n = 0;
- if (stat(lockfile,&status) >= 0) {
- D4("%s Lockfile \"%s\" exists.",getime(),lockfile);
- n = lockup();
- D4("%s Lockfile \"%s\" gone.",getime(),lockfile);
- }
- if (n) { /* Port may be screwed up */
- opendev(); /* Close and reopen it */
- restdev(); /* Get it into proper state */
- }
- D4("lockwait:Returned after %d waits.",n);
- return n;
- }
- \!Funky\!Stuff\!
- echo file: main.c
- cat > main.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- #include <signal.h>
- static char id[] = "@(#)RELEASE: 1.0 Sep 20 1986 ~jc/uutty";
- /*
- ** uutty device [option]...
- **
- ** This is John Chambers' own personal serial-port daemon,
- ** to watch a port, determine what sort of critter is at the
- ** other end of the line, and engage it in a semi-intelligent
- ** dialog. The primary goal of this version, uutty, is to
- ** make it possible to use direct links (null modems) freely in
- ** both directions, without the problems caused by the getty(1)
- ** program. In particular, it allows the use of the uucp package
- ** (including uux and cu) in both directions across a line.
- **
- ** Another thing uutty is good for is using a modem in either
- ** without needing any special actions.
- **
- ** Uutty is a thinly-disguised "state machine" whose basic
- ** behavior is determined by a global "state variable" ss
- ** and a string of input characters. The state variable is
- ** simply an integer that encodes the last action performed.
- ** An input routine is called, and when it returns, the input
- ** is examined to determine the program's next action. Normally,
- ** this action is to produce an output string, change the state
- ** variable, and wait for the next input.
- **
- ** The major intent of this program is to do a login interview,
- ** but to ignore anyone at the other end of the line that acts
- ** like it's trying to log us in. If getty or this program is
- ** at the other end, the result will be silence until someone
- ** sends a CR or LF (which elicits "login:") or something that
- ** is acceptable as a login id. Note in particular that input
- ** containing colons and spaces will be ignored.
- **
- ** The other major intent is to cooperate with any software that
- ** sets the uucp lockfiles ("/usr/spool/uucp/LCK..<device>"), by
- ** checking for such lockfiles frequently, and sleeping any time
- ** they are found. This program never creates a lockfile; it just
- ** sleeps when someone else creates one. Thus, this program may
- ** be left running on a port used by uucp, cu, or other such serial-
- ** port users. There is a slight possibility that this program
- ** may eat up part of the first response from the port, but that
- ** is rarely much of a problem. One or two CRs will usually suffice
- ** to elicit a "gin:" prompt from the other end.
- **
- ** A third, minor intent is to recognize overly-intelligent modems,
- ** and refuse to become engaged in a conversations with them. This
- ** is done primarily by rejecting input that contains whitespace or
- ** special characters, or which contains only upper-case letters.
- ** This will handle the error messages produced by most commercial
- ** modems. However, users may wish to add to the code that examines
- ** login ids and passwords, and add more checks for specific modems.
- **
- ** You may notice that this program is full of Dx(...) debug calls.
- ** These are defined in dbg.h, and may be suppressed fairly easily.
- ** Most C compilers will react to, for instance:
- ** #define D9 if(0) dmsg
- ** by generating no code at all. You might think this would make
- ** your program smaller and faster, and you'd be partly right. It
- ** will definitely be smaller, but probably not much faster. Anyhow,
- ** the speed of this program isn't much of an issue; if it gets into
- ** a feedback loop with a modem, you don't much care how efficiently
- ** it brings your system to its knees! It's probably a wiser idea
- ** to leave most of the diagnostic junk in. You'll be surprised at
- ** how useful it can be to have that stuff in an audit trail.
- **
- ** Some of the options recognized are:
- **
- ** -b<n> use a baud rate of <n>. Final "00" may be omitted.
- **
- ** -c<n> slow down by counting to <n> between output chunks.
- **
- ** -d<n> debug level <n>; default is -d1.
- **
- ** -e<s> exit string <s> to send when terminating.
- **
- ** -f fork a subprocess for starting shells.
- **
- ** -i<s> initialization string <s> is sent whenever it is
- ** decided that the other end is insane or jabbering.
- **
- ** -l create uucp lockfiles before starting a shell; delete
- ** them afterwards. This option implies the -f option.
- **
- ** -n<s> nudge string <s> is sent when this program wants a response.
- **
- ** -p<f> port to use, where <f> is usually /dev/tty??. This is
- ** the same as using <f> without any prefix.
- **
- ** -s<n> sleep <n> seconds between output chunks.
- **
- ** -x<n> debug level <n>.
- **
- ** To be responsible, I should repeat the warning stated elsewhere:
- ** with debug level -d2 or higher, uutty writes everything it sees,
- ** including unencrypted login ids and passwords, to its diagnostic
- ** output stream (audit trail). This makes it a Trojan Horse of the
- ** first kind. If you are security-conscious, you might take steps
- ** to hide the audit trail, and purge it frequently.
- **
- ** In any case, the audit trail grows without bounds, so you will want
- ** to take steps to keep it within bounds. The easiest way is with an
- ** entry in crontab that starts up a daily cleanup script (/etc/cleanup
- ** is a real good name for it). This script can move the uutty audit
- ** trails to a different name, to produce one level of backup.
- */
- main(ac,av)
- char**av;
- { int i, r;
-
- time(&currtime); /* Note the start time */
- progname = av[0]; /* For debug output */
- prgnam = lastfield(progname,'/');
- D4("prgnam=\"%s\" progname=\"%s\"",prgnam,progname);
- euid = geteuid();
- egid = getegid();
- ruid = getuid();
- rgid = getgid();
- D3("euid=%d egid=%d ruid=%d rgid=%d",euid,egid,ruid,rgid);
- args(ac,av); /* Process command-line args */
- if (debug) { /* Generate first entries in audit trail */
- P("+--------------------------------------------------------------------+");
- P("%s %s started.",getime(),progname);
- }
- timeout = 255; /* Use max timeout on reads */
- sig(); /* Intercept all the signals */
- slowfl = (count > 0) || (slow > 0);
- opendev(); /* Open the port which we are to use */
- if (dev != 0) {close(0); i = dup(dev); D3("File %d=\"%s\"",i,device);}
- if (dev != 1) {close(1); i = dup(dev); D3("File %d=\"%s\"",i,device);}
- lockwait(); /* First check to see if it's busy */
- /*
- ** The code to handle raw, 8-bit communication get a bit weird from
- ** system to system. Here, we try to trap the initial state of the
- ** port, so that when we die, we can first restore it.
- */
- #ifdef SYS5
- if (raw && isatty(dev)) { /* We will want to restore its initial state */
- D5("main:before ioctl(%d,%d,%06lX)",dev,TCGETA,&trminit);
- i = ioctl(dev,TCGETA,&trminit); /* Note initial state of terminal */
- D5("main: after ioctl(%d,%d,%06lX)=%d",dev,TCGETA,&trminit,i);
- D7("main: %d:\tcflag=%06o",dev,trminit.c_cflag);
- D7("main: %d:\tiflag=%06o",dev,trminit.c_iflag);
- D7("main: %d:\tlflag=%06o",dev,trminit.c_lflag);
- D7("main: %d:\toflag=%06o",dev,trminit.c_oflag);
- termfl = 1;
- /* crlf = "\n\r"; ** Not needed on Unix systems */
- }
- #endif
- restdev(); /* Get port to desired (raw, very public) state */
- #ifdef SYS5
- /*
- ** The following functions suffice to find, update, and write
- ** the appropriate entry in the /etc/utmp file, which on SYS/V
- ** is the record of logged-in users. This may well have to be
- ** changed for other systems. The hope here is that this is a
- ** reasonable way to modularize the job, though the names may
- ** not be ideal...
- */
- D8("main:before findutmp()");
- up = findutmp(); /* Try to locate our /etc/utmp entry */
- D7("main: after findutmp()=%06lX",up);
- D8("main:before fillutmp(\"%s\",%X,\"%s\",%d)",prgnam,(char*)0,devfld,LOGIN_PROCESS);
- fillutmp(prgnam,(char*)0,devfld,LOGIN_PROCESS);
- D7("main: after fillutmp()");
- D8("pswd:before pututline(%06lX)",up);
- pututline(up); /* Put modified line into /etc/utmp */
- D7("pswd: after pututline(%06lX)",up);
- #endif
- r = talk(); /* Attempt a conversation */
- die(r); /* If we should ever decide to stop */
- return 0; /* Paranoia! */
- }
- \!Funky\!Stuff\!
- echo file: makeraw.c
- cat > makeraw.c << '\!Funky\!Stuff\!'
- /* Tell the device driver to do raw I/O on the device.
- * Unfortunately, this is done in different ways on different
- * brands of Unix. Make sure that your system is included
- * somewhere in the following list.
- */
- #include <dbg.h>
- #ifdef BERK
- # include <sgtty.h>
- int ldisc = NETLDISC;
- struct sgttyb sgttyb;
- #endif
- #ifdef PCIX
- # include <termio.h>
- struct termio termio;
- #endif
- #ifdef SYS5
- # include <termio.h>
- struct termio termio;
- #endif
- extern int baudmask; /* CBAUD mask, if baud rate specified */
- extern int errno;
- int flowcontrol = 1;
- uint timeout = 100; /* Timeout in 0.1 second quanta */
-
- makeraw(fn)
- int fn; /* File number */
- { int i;
-
- D5("makeraw(%d)",fn);
- errno = 0;
- #ifdef SYS5
- i = ioctl(fn,TCGETA,&termio);
- D4("makeraw: %d:\tcflag=%06o [old]",fn,termio.c_cflag);
- D4("makeraw: %d:\tiflag=%06o [old]",fn,termio.c_iflag);
- D4("makeraw: %d:\tlflag=%06o [old]",fn,termio.c_lflag);
- D4("makeraw: %d:\toflag=%06o [old]",fn,termio.c_oflag);
- D5("makeraw: ioctl(fn=%d,TCGETA=%d,&termio=%08X)=%d",fn,TCGETA,&termio,i);
- if (baudmask) /* Wipe out all of cflag but speed */
- termio.c_cflag = baudmask;
- else termio.c_cflag &= CBAUD;
- termio.c_cflag |= CS8 | CREAD | HUPCL;
- termio.c_iflag = flowcontrol? (IXON | IXANY | IXOFF): 0;
- termio.c_lflag = 0;
- termio.c_oflag = 0;
- termio.c_cc[4] = 0; /* Number of bytes to buffer up */
- termio.c_cc[5] = timeout; /* Timeout in 0.1 sec units */
- D4("makeraw: %d:\tcflag=%06o [new]",fn,termio.c_cflag);
- D4("makeraw: %d:\tiflag=%06o [new]",fn,termio.c_iflag);
- D4("makeraw: %d:\tlflag=%06o [new]",fn,termio.c_lflag);
- D4("makeraw: %d:\toflag=%06o [new]",fn,termio.c_oflag);
- i = ioctl(fn,TCSETA,&termio);
- #endif
- #ifdef SYS3
- i = ioctl(fn,TCGETA,&termio);
- termio.c_iflag |= IGNCR | IXON | IXANY | IXOFF;
- termio.c_lflag = 0;
- D5("makeraw: \tcflag=%06o",termio.c_cflag);
- D5("makeraw: \tiflag=%06o",termio.c_iflag);
- D5("makeraw: \tlflag=%06o",termio.c_lflag);
- D5("makeraw: \toflag=%06o",termio.c_oflag);
- i = ioctl(fn,TCSETA,&termio);
- #endif
- #ifdef BERK /* Berkeley Unix has its own conventions */
- i = ioctl(fn,TIOCGETP,&sgttyb);
- sgttyb.sg_flags = RAW | TANDEM;
- ioctl(fn,TIOCSETP,&sgttyb);
- if (errno) {
- E("makeraw: Can't do raw i/o on \"%s\"",fnnam);
- exit(-1);
- }
- #endif
- D5("makeraw: %d is now raw",fn);
- }
- \!Funky\!Stuff\!
- echo file: makesane.c
- cat > makesane.c << '\!Funky\!Stuff\!'
- /* Tell the device driver to do normal I/O on the device.
- * Unfortunately, this is done in different ways on different
- * brands of Unix. Make sure that your system is included
- * somewhere in the following list.
- */
- #include <dbg.h>
- #ifdef BERK
- # include <sgtty.h>
- int ldisc = NETLDISC;
- struct sgttyb sgttyb;
- #endif
- #ifdef PCIX
- # include <termio.h>
- struct termio termio;
- #endif
- #ifdef SYS5
- # include <termio.h>
- static struct termio trmstat;
- #endif
- extern int errno;
- extern int baudmask; /* CBAUD mask if baud rate specified */
-
- makesane(fn)
- int fn; /* File number */
- { int i;
-
- D5("makesane(%d)",fn);
- errno = 0;
- #ifdef SYS5
- i = ioctl(fn,TCGETA,&trmstat);
- if (debug >= 4) {
- P("makesane: %d:\tcflag=%06o [old]",fn,trmstat.c_cflag);
- P("makesane: %d:\tiflag=%06o [old]",fn,trmstat.c_iflag);
- P("makesane: %d:\tlflag=%06o [old]",fn,trmstat.c_lflag);
- P("makesane: %d:\toflag=%06o [old]",fn,trmstat.c_oflag);
- }
- D5("makesane: ioctl(fn=%d,TCGETA=%d,&trmstat=%08X)=%d",fn,TCGETA,&trmstat,i);
- /*
- ** The following was given by "stty -a" on one SYS/V machine:
- ** speed 9600 baud; line = 2; intr = ^c; quit = ^\; erase = ^H; kill = ^x; eof = ^d; eol = ^@;susp = ^z;dsus = ^y
- ** -parenb -parodd cs8 -cstopb -hupcl cread -clocal -tostop
- ** -ignbrk brkint ignpar -parmrk -inpck istrip -inlcr -igncr icrnl -iuclc
- ** ixon -ixany -ixoff
- ** isig icanon -xcase echo echoe echok -echonl -noflsh
- ** opost -olcuc onlcr -ocrnl -onocr -onlret -ofill -ofdel tab3
- speed 9600 baud; line = 2; intr = ^c; quit = ^\; erase = DEL; kill = ^x; eof = ^d; eol = ^@;susp = ^z;dsus = ^y
- -parenb -parodd cs8 -cstopb -hupcl cread -clocal -tostop
- -ignbrk brkint ignpar -parmrk -inpck istrip -inlcr -igncr icrnl -iuclc
- ixon -ixany -ixoff
- isig icanon -xcase echo echoe echok -echonl -noflsh
- opost -olcuc onlcr -ocrnl -onocr -onlret -ofill -ofdel tab3
- */
- trmstat.c_cflag &= CBAUD; /* Save the speed */
- if (baudmask) {
- D4("makesane: baudmask=0%o",baudmask);
- trmstat.c_cflag = baudmask; /* Set a different speed */
- }
- trmstat.c_cflag |= HUPCL | CREAD | CS8;
- trmstat.c_iflag = BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
- trmstat.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
- trmstat.c_oflag = OPOST | ONLCR | TAB3;
- trmstat.c_cc[0] = 0x03; /* INTR = ^C */
- trmstat.c_cc[1] = 0x1C; /* QUIT = ^\ */
- trmstat.c_cc[2] = 0x10; /* ERASE= ^H [BS] */
- trmstat.c_cc[3] = 0x18; /* KILL = ^X */
- trmstat.c_cc[4] = 0x04; /* EOF = ^D */
- trmstat.c_cc[5] = 0; /* EOL char */
- trmstat.c_cc[6] = 0; /* EOL2 char */
- /* trmstat.c_cc[7] = __; ** Reserved */
- trmstat.c_cc[8] = 0x1A; /* SUSP = ^Z */
- trmstat.c_cc[9] = 0x19; /* SUSP = ^Y */
- if (debug >= 5) {
- P("makesane: %d:\tcflag=%06o [new]",fn,trmstat.c_cflag);
- P("makesane: %d:\tiflag=%06o [new]",fn,trmstat.c_iflag);
- P("makesane: %d:\tlflag=%06o [new]",fn,trmstat.c_lflag);
- P("makesane: %d:\toflag=%06o [new]",fn,trmstat.c_oflag);
- Hexdnm(&trmstat.c_cc[0],NCC,"c_cc:");
- }
- i = ioctl(fn,TCSETA,&trmstat);
- #endif
- #ifdef SYS3 /* Note: Tested only on PC/IX */
- i = ioctl(fn,TCGETA,&trmstat);
- trmstat.c_cflag |= HUPCL | PARENB | CREAD | CS7;
- trmstat.c_iflag = BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
- trmstat.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
- trmstat.c_oflag = OPOST | ONLCR | TAB3;
- D5("makesane: \tcflag=%06o",trmstat.c_cflag);
- D5("makesane: \tiflag=%06o",trmstat.c_iflag);
- D5("makesane: \tlflag=%06o",trmstat.c_lflag);
- D5("makesane: \toflag=%06o",trmstat.c_oflag);
- i = ioctl(fn,TCSETA,&trmstat);
- #endif
- #ifdef BERK /* Note: Tested only on 4.2 */
- i = ioctl(fn,TIOCGETP,&sgttyb);
- sgttyb.sg_flags = SANE | TANDEM;
- ioctl(fn,TIOCSETP,&sgttyb);
- if (errno) {
- E("makesane: Can't do sane i/o on \"%s\"",fnnam);
- exit(-1);
- }
- #endif
- D5("makesane: %d is now sane.",fn);
- }
- \!Funky\!Stuff\!
- echo file: nextbyte.c
- cat > nextbyte.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Extract one byte from the port's input buffer, triggering
- ** a read if necessary. If no data is available within the
- ** timeout limit, -1 is returned. All other return values
- ** should be small positive integers, in [1,255].
- */
- nextbyte()
- { int i;
-
- D9("nextbyte()");
- loop:
- if (ibfa >= ibfz) {
- errno = 0;
- lockwait();
- D9("nextbyte:before read(%d,%06lX,%d)",dev,ibuf,IBUF);
- if ((i = read(dev,ibuf,IBUF)) <= 0) {
- D9("nextbyte: read(%d,%06lX,%d)=%d\t[errno=%d]"
- ,dev,ibuf,IBUF,i,errno);
- Fail;
- }
- D8("nextbyte: after read(%d,%06lX,%d)=%d\t[errno=%d]"
- ,dev,ibuf,IBUF,i,errno);
- if (debug >= 4) {
- dbgtimep = getime();
- Hexdnm(ibuf,i,"Read:");
- }
- if (echoing) {
- write(dev,ibuf,i);
- }
- ibfa = ibuf;
- ibfz = ibuf + i;
- *ibfz = '\0';
- }
- i = ASCII(*ibfa++);
- D9("nextbyte()=%02X='%c'",i,dsp(i));
- if (i == 0) Loop; /* Don't return nulls */
- return i;
- fail:
- D8("nextbyte()=-1 [FAILURE]");
- return -1;
- }
- \!Funky\!Stuff\!
- echo file: opendev.c
- cat > opendev.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Close and re-open the port.
- */
- opendev()
- {
- D6("opendev()");
- if (dev >= 0) close(dev);
- if (device) {
- if ((dev = open(device,2)) < 0) {
- E("FATAL ERROR\n%s Can't open \"%s\"\t[errno=%d]",getime(),device,errno);
- die(1);
- }
- if (debug) P("%s Opened dev=%d=\"%s\".",getime(),dev,device);
- }
- return dev;
- }
- \!Funky\!Stuff\!
- echo file: option.c
- cat > option.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Process an option string. Note that we get
- ** a pointer to the initial char, usually '-'.
- */
- extern int baudmask; /* CBAUD mask, if baud rate specified */
- extern int baudrate; /* Actual baud rate */
-
- option(op)
- char*op;
- { int n;
-
- D4("option(\"%s\")",op);
- switch (op[1]) { /* Which option? */
- default:
- sprintf(stderr,"Unknown option \"%s\" ignored.\n",op);
- break;
- case 'B': /* Set baud rate */
- case 'b':
- n = sscanf(op+2,"%u",&baudrate);
- if (n < 1) baudrate = 1;
- D3("baudrate=%u\n",baudrate);
- switch (baudrate) {
- case 12: case 1200: baudmask = B1200; break;
- case 24: case 2400: baudmask = B2400; break;
- case 48: case 4800: baudmask = B4800; break;
- case 96: case 9600: baudmask = B9600; break;
- default: E("Can't handle baud rate of %d",baudrate);
- baudrate = baudmask = 0;
- }
- break;
- case 'C': /* Count between I/O operations */
- case 'c':
- n = sscanf(op+2,"%u",&count);
- if (n < 1) count = 1;
- D3("count=%u\n",count);
- slowfl = count || slow;
- break;
- case 'D': /* Set debug level */
- case 'd':
- case 'X': /* Set debug level */
- case 'x':
- n = sscanf(op+2,"%u",&debug);
- if (n < 1) debug = 1;
- D3("debug=%d\n",debug);
- break;
- case 'E':
- case 'e': /* Exit message */
- if (op[2]) { /* -e"msg" is exit message */
- m_exit = op + 2;
- D3("m_exit=\"%s\"",m_exit);
- } else { /* -e turns on echoing */
- echoing = echofl = 1;
- D3("echofl=%d",echofl);
- }
- break;
- case 'F':
- case 'f': /* Fork subprocesses for a shells */
- forkfl++;
- D3("forkfl=%d",forkfl);
- break;
- case 'H':
- case 'h': /* Display "help" messages */
- help();
- break;
- case 'I':
- case 'i': /* Initialization message */
- m_init = op + 2;
- D3("m_init=\"%s\"",m_init);
- break;
- case 'L':
- case 'l': /* Create lockfile on login */
- lockfl++;
- forkfl++;
- D3("forkfl=%d lockfl=%d",forkfl,lockfl);
- break;
- case 'N':
- case 'n': /* Nudge message */
- m_nudge = op + 2;
- D3("m_nudge=\"%s\"",m_nudge);
- break;
- case 'P':
- case 'p': /* Port name */
- device = op + 2;
- D3("device=\"%s\"",device);
- break;
- case 'R':
- case 'r': /* Raw I/O [default=TRUE] */
- n = sscanf(op+2,"%d",&raw);
- if (n < 1) raw = 1;
- D3("raw=%d\n",raw);
- break;
- case 'S':
- case 's': /* Slow output, sleep(slow) between buffers */
- n = sscanf(op+2,"%d",&slow);
- if (n < 1) slow = 1;
- D3("slow=%d\n",slow);
- break;
- }
- return 0;
- }
- \!Funky\!Stuff\!
- echo file: pread.c
- cat > pread.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Read a response from the debugger into a buffer. Note the three
- ** stop conditions: finding an EOL char; filling the buffer; timeout.
- */
- pread(stopch,bp,bs)
- int stopch;
- char*bp;
- int bs;
- { int c, n;
- uint reads;
-
- D4("pread(stopch=%02X,bp=%06lX,bs=%d)",stopch,bp,bs);
- n = reads = 0;
- while (n < bs) {
- c = nextbyte(); /* Next char from port */
- if (c <= 0) { /* No data returned? */
- if (debug >= 4)
- if (reads) P("pread: %d reads",reads);
- if (++reads > l_reads) {
- errno = ETIMEOUT; /* Timeout if too many */
- D3("Input timeout...");
- Fail; /* Timeout; return what we have */
- }
- continue;
- }
- D9("pread: c=%02X='%c' bp=%06lX bs=%d",c,dsp(c),bp,bs);
- c &= iomask; /* Trim it to 7 bits */
- if (c == 0) continue; /* Ignore nulls */
- *bp++ = c; /* Note the EOL char is returned */
- ++n; /* Count the input chars */
- --bs; /* Decr count of bytes wanted */
- if (c == stopch) Done; /* Assorted EOL chars */
- switch (c) {
- case 0x03: /* ^C = ETX */
- if (debug) P("%s: ^C in input, quitting [id]",getime());
- die(0);
- case '>' :
- case '\r':
- case '\n':
- case ':' :
- case '%' :
- case 0x04: /* ^D = EOT */
- case 0x06: /* ^D = ACK */
- case 0x15: /* ^U = NAK */
- Done;
- }
- reads = 0; /* Got data; reset timeout counter */
- }
- done:
- *bp = 0; /* Final null for debugging */
- fail:
- return n;
- }
- \!Funky\!Stuff\!
- echo file: pswd.c
- cat > pswd.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** We have received something that is believed to be a password.
- ** It is this routine's job to combine it with the current userid,
- ** and determine whether the combination is acceptable. This
- ** routine should work on most Unix systems, but who knows?
- */
- pswd(rp)
- char *rp;
- { char *p, *q;
- int i;
- struct passwd *pp;
-
- D4("pswd: r=\"%s\" ss=%d",rp,ss);
- for (p=rp; *p; ++p) { /* Examine the chars for acceptability */
- switch(*p) {
- case ':': /* Colons aren't legal */
- D3("Invalid char '%c' in password",*p);
- Fail;
- case '\r':
- case '\n':
- *p = 0;
- goto gotit;
- case '!': /* Special goodie for killing daemon */
- if (p[1] == 'Q') {
- if (debug) P("%s: !Q in input, quitting [id]",getime());
- die(0);
- }
- default:
- continue;
- }
- }
- gotit: /* Make a copy of the supposed id */
- p = rp;
- q = passwd;
- while (*p && q<passwd+PASSWD)
- *q++ = *p++;
- *q = 0;
- if (debug >= 3) P("%s PASSWD=\"%s\"",getime(),passwd);
- D3("userid:\"%s\"",userid);
- D3("pswd:\"%s\"",passwd);
- pp = getpwnam(userid);
- if (pp == 0) {
- D1("Login \"%s\" incorrect.",userid);
- D3("userid \"%s\" not found.",userid);
- Fail;
- }
- if (debug >= 6) Hexdnm(pp,sizeof(*pp),"Passwd:");
- D4("pw_name =\"%s\"",pp->pw_name);
- D4("pw_passwd=\"%s\"",pp->pw_passwd);
- D4("pw_dir =\"%s\"",pp->pw_dir);
- D4("pw_shell =\"%s\"",pp->pw_shell);
- D5("pswd:before crypt(\"%s\",\"%s\")",passwd,pp->pw_passwd);
- p = crypt(passwd,pp->pw_passwd);
- D5("pswd: after crypt(\"%s\",\"%s\")=\"%s\"",passwd,pp->pw_passwd,p);
- if (strcmp(p,pp->pw_passwd)) {
- Pwrite("Login incorrect.\r\n");
- D3("pswd \"%s\" not correct.",passwd);
- Fail;
- }
- D3("Login: uid=%d=\"%s\" group=%d accepted.",pp->pw_uid,pp->pw_name,pp->pw_gid);
- /*
- ** To do the next few changes, we probably need to be a super-user:
- */
- #ifdef SYS5
- /*
- ** Attempt to build a utmp structure.
- */
- errno = 0;
- up = 0;
- D5("before ttyslot()");
- i = ttyslot(); /* Identify our /etc/utmp line */
- D4("ttyslot()=%d\t[errno=%d]",i,errno);
- findutmp();
- p = 0;
- fillutmp(pp->pw_name,p,devfld,USER_PROCESS);
- D4("pswd:before pututline(%06lX)",up);
- pututline(up);
- #endif
- errno = 0;
- i = chmod(device,0644); /* Restrict terminal access to owner */
- D4("chmod(\"%s\",0%o)=%d\t[errno=%d]",device,0644,i,errno);
- D3("Change \"%s\" to user %d=%s, group %d, permissions 644.",device,pp->pw_uid,pp->pw_name,pp->pw_gid);
- i = chown(device,pp->pw_uid,pp->pw_gid); /* Change terminal's group */
- D4("chown(\"%s\",%d,%d)=%d",device,pp->pw_uid,pp->pw_gid,i);
- D3("New group %d.",pp->pw_gid);
- i = setgid(pp->pw_gid); /* Change terminal's owner */
- D4("setgid(%d)=%d",pp->pw_gid,i);
- if (i < 0) Fail;
- D3("New user %d.",pp->pw_uid);
- i = setuid(pp->pw_uid); /* Change to login id */
- D4("setuid(%d)=%d",pp->pw_uid,i);
- if (i < 0) Fail;
- D3("New directory \"%s\"",pp->pw_dir);
- i = chdir(pp->pw_dir); /* Move to login directory */
- D4("chdir(\"%s\")=%d",pp->pw_dir,i);
- if (i < 0) Fail;
- /*
- ** Invoke the login shell.
- */
- D5("pswd:before exec(1,\"%s\",%lX)",pp->pw_shell,pp);
- exec(1,pp->pw_shell,pp); /* Start up a shell */
- D5("pswd: after exec(1,\"%s\",%lX)",pp->pw_shell,pp);
- target = "?"; /* We shouldn't get here */
- fail:
- D4("pswd(\"%s\") FAILED.",rp);
- if (echofl ) Awrite("\r\nLogin incorrect.");
- if (m_login) {
- Awrite(m_login);
- ss = S_LOGIN; /* Note login prompt sent */
- D4("State %d=%s",ss,gestate());
- }
- sleep(1);
- return 0;
- }
- \!Funky\!Stuff\!
- echo file: pwrite.c
- cat > pwrite.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Write a character string to the port, stopping at the first null.
- ** This will be done slowly iff slowfl is turned on.
- */
- pwrite(msg)
- char*msg;
- { int i, n;
- char c, *p;
-
- D5("pwrite(%08lX)",msg);
- n = strlen(msg);
- if (debug) {
- dbgtimep = getime();
- if (debug >= 2) Ascdnm(msg,n,"Send:");
- if (debug >= 4) Hexdnm(msg,n,"Send:");
- }
- if (slowfl) {
- D8("port_wr:slow=%d",slow);
- p = msg;
- while (c = *p++) {
- Slowly;
- D9("port_wr:before write(%d,%06lX,%d)",dev,&c,1);
- i = write(dev,&c,1);
- D9("port_wr: after write(%d,%06lX,%d)=%d",dev,&c,1,i);
- if (i <= 0) {
- if (debug) P("%s: write failed, quitting.",getime());
- die(2);
- }
- }
- } else {
- D9("port_wr:before write(%d,\"%s\",%d)",dev,msg,n);
- i = write(dev,msg,n);
- D9("port_wr: after write()=%d\t[errno=%d]",i,errno);
- }
- }
- \!Funky\!Stuff\!
- echo file: restdev.c
- cat > restdev.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Set the device to our desired (raw) state. This may only
- ** work if we are the super-user. This routine, such as it is,
- ** should work on just about any Unix system. See makeraw.c
- ** for the real system-dependent stuff.
- */
- restdev()
- { int i;
-
- D6("restdev()");
- makeraw(dev); /* We want to do raw I/O */
- errno = 0;
- D2("Change \"%s\" to user %d, group %d, permissions 666.",device,euid,egid);
- i = chown(device,euid,egid); /* Try to get ownership */
- D4("restdev: chown(\"%s\",%d,%d)=%d",device,euid,egid,i);
- errno = 0;
- i = chmod(device,0666); /* Make it publicly accessible */
- D4("restdev: chmod(\"%s\",0%o)=%d\t[errno=%d]",device,0666,i,errno);
- return i;
- }
- \!Funky\!Stuff\!
- echo file: resync.c
- cat > resync.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Discard buffered input, and try to get us to a start where
- ** the next input will be a response to the most recent (or next)
- ** output.
- */
- resync()
- {
- if (ibfa < ibfz) {
- dbgtimep = getime();
- if (debug >= 2) Ascdnm(ibfa,ibfz-ibfa,"Drop:");
- if (debug >= 4) Hexdnm(ibfa,ibfz-ibfa,"Drop:");
- restdev(); /* Make sure the device is OK */
- sleep(5); /* Try not to respond to garbage */
- }
- ibfa = ibfz+1;
- }
- \!Funky\!Stuff\!
- echo file: sendbrk.c
- cat > sendbrk.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** If fd is a terminal-type device, and ioctl(-,TCSBRK,0) works,
- ** this will send a break signal down the line, which may (or may
- ** not) get the attention of whatever is at the other end.
- */
- sendbrk(fd)
- { int i;
-
- D4("BREAK");
- errno = 0;
- D5("sendbrk:before ioctl(fd=%d,TCSBRK=%d,0)",fd,TCSBRK);
- i = ioctl(fd,TCSBRK,0);
- D5("sendbrk: after ioctl(fd=%d,TCSBRK=%d,0)=%d [errno=%d]",fd,TCSBRK,i,errno);
- if (i<0 || errno)
- D2("ioctl(%d,TCSBRK=%d,0)=%d\t[errno=%d]",fd,TCSBRK,i,errno);
- return i;
- }
- \!Funky\!Stuff\!
- echo file: shprompt.c
- cat > shprompt.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** We seem to have gotten a shell prompt, but it's kinda hard to be sure.
- ** This routine is somewhat of a relic in uutty, but has been left here
- ** because you might want to deal with this case. What we try to do
- ** basically is to get the shell to logout.
- */
- shprompt(rp) char *rp;
- {
- D5("shprompt(\"%s\")",rp);
- target = "shell";
- switch(ss) {
- case S_INIT:
- case S_PASSWD:
- default:
- E("****Can't handle shell prompt \"%s\" in state %d=%s.",rp,ss,gestate());
- Awrite("exit\r"); /* This terminates most shells */
- Awrite("logout\r"); /* This terminates other shells */
- Awrite("\4\3"); /* This works with still others */
- if (m_exit) Awrite(m_exit); /* Other optional exit message */
- if (m_init) Awrite(m_init); /* Try to tell the modem to quit */
- ss = S_IDLE;
- D4("State %d=%s",ss,gestate());
- }
- }
- \!Funky\!Stuff\!
- echo file: sig.c
- cat > sig.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- #include <signal.h>
-
- sig_1() {P("Signal 1 [SIGHUP]" ); fflush(stdout); die( 1);}
- sig_2() {P("Signal 2 [SIGINT]" ); fflush(stdout); die( 2);}
- sig_3() {P("Signal 3 [SIGQUIT]"); fflush(stdout); die( 3);}
- sig_4() {P("Signal 4 [SIGILL]" ); fflush(stdout); die( 4);}
- sig_5() {P("Signal 5 [SIGTRAP]"); fflush(stdout); die( 5);}
- sig_6() {P("Signal 6 [SIGIOT]" ); fflush(stdout); die( 6);}
- sig_7() {P("Signal 7 [SIGEMT]" ); fflush(stdout); die( 7);}
- sig_8() {P("Signal 8 [SIGFPE]" ); fflush(stdout); die( 8);}
- sig_9() {P("Signal 9 [SIGKILL]"); fflush(stdout); die( 9);}
- sig10() {P("Signal 10 [SIGBUS]" ); fflush(stdout); die(10);}
- sig11() {P("Signal 11 [SIGSEGV]"); fflush(stdout); die(11);}
- sig12() {P("Signal 12 [SIGSYS]" ); fflush(stdout); die(12);}
- sig13() {P("Signal 13 [SIGPIPE]"); fflush(stdout); die(13);}
- sig14() {P("Signal 14 [SIGALRM]"); fflush(stdout); die(14);}
- sig15() {P("Signal 15 [SIGTERM]"); fflush(stdout); die(15);}
- sig16() {P("Signal 16 [SIGADDR]"); fflush(stdout); die(16);}
- sig17() {P("Signal 17 [SIGZERO]"); fflush(stdout); die(17);}
- sig18() {P("Signal 18 [SIGCHK]" ); fflush(stdout); die(18);}
- sig19() {P("Signal 19 [SIGOVER]"); fflush(stdout); die(19);}
- sig20() {P("Signal 20 [SIGPRIV]"); fflush(stdout); die(20);}
- sig21() {P("Signal 21 [SIGUSR1]"); fflush(stdout); die(21);}
- sig22() {P("Signal 22 [SIGUSR2]"); fflush(stdout); die(22);}
-
- /* Catch all the signals we can:
- */
- sig()
- {
- signal( 1,sig_1);
- signal( 2,sig_2);
- signal( 3,sig_3);
- signal( 4,sig_4);
- signal( 5,sig_5);
- signal( 6,sig_6);
- signal( 7,sig_7);
- signal( 8,sig_8);
- signal( 9,sig_9);
- signal(10,sig10);
- signal(11,sig11);
- signal(11,sig11);
- signal(12,sig12);
- signal(13,sig13);
- signal(14,sig14);
- signal(15,sig15);
- signal(16,sig16);
- signal(17,sig17);
- signal(18,sig18);
- signal(19,sig19);
- signal(20,sig20);
- signal(21,sig21);
- signal(22,sig22);
- }
- \!Funky\!Stuff\!
- echo file: slowly.c
- cat > slowly.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** This routine handles requests to do things slowly.
- ** Note the two ways of delaying: sleeping for "slow"
- ** seconds, or counting down from "count" to 1.
- */
- slowly()
- { uint u;
-
- D8("slowly() slow=%d count=%d",slow,count);
- if (slow > 0) {
- D8("slowly: slow=%d",slow);
- sleep(slow);
- }
- for (u=count; u; u--) ;
- D8("slowly() done");
- }
- \!Funky\!Stuff\!
- echo file: st.c
- cat > st.c << '\!Funky\!Stuff\!'
- #include "dbg.h"
- /*
- ** Assorted string-manipulation subroutines.
- */
- /* Match a null-terminated string against the initial portion
- ** of another string. If the match succeeds, return its length;
- ** else return 0.
- */
- int st_init(x,y)
- char *x;
- char *y;
- { char *s;
- char *t;
-
- s = x;
- t = y;
- while (*s)
- if (*s++ != *t++) goto fail;
- D9("st_init(\"%s\",\"%s\")=%d",x,y,s-x);
- return(s - x);
- fail:
- D9("st_init(\"%s\",\"%s\")=%d",x,y,0);
- return 0;
- }
- /* Return the int value of the trailing digits of a null-terminated string.
- ** Note that non-numeric chars reset the value, so only digits that follow
- ** all non-numerics are used. Also, only the last '-' is effective. Thus
- ** "15-x-37" gives the value 37.
- */
- int st_ival(s)
- char *s;
- { int c, val, sign;
-
- sign = val = 0;
- while (c = *s++)
- if ('0'<=c && c<='9')
- val = (val * 10) + (c - '0');
- else if (c == '-')
- sign = c;
- else
- sign = val = 0;
- return(sign ? -val : val);
- }
- /* Convert a long to an ASCII string.
- ** Return pointer to byte just after the value.
- */
- char * st_ltoa(l,a)
- long l;
- char *a;
- {
- if (l < 0) {*a++ = '-'; l = -l;}
- if (l > 9) a = st_ltoa((l/10),a);
- *a++ = '0' + (l % 10);
- return a;
- }
- /* Return the long value of the trailing digits of a null-terminated string.
- ** Note that non-numeric chars reset the value, so only digits that follow
- ** all non-numerics are used. Also, only the last '-' is effective. Thus
- ** "15-x-37" gives the value 37.
- */
- long st_lval(s)
- char *s;
- { int c, sign;
- long val;
-
- val = sign = 0;
- D4("st_lval: sign=%d val=%ld",sign,val);
- while (c = *s++) {
- if ('0'<=c && c<='9')
- val = (val * 10) + (c - '0');
- else if (c == '-')
- sign = c;
- else
- val = sign = 0;
- D4("st_lval: sign=%d val=%ld c=%02x='%c'",sign,val,c,dsp(c));
- }
- return(sign ? -val : val);
- }
- \!Funky\!Stuff\!
- echo file: talk.c
- cat > talk.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** This routine assumes that it is talking to a port connected
- ** to a VMEbus device with an on-board debugger. It exchanges
- ** some pleasantries to verify this fact, then procedes to ask
- ** the debugger to show it the requested chunk of its memory.
- */
- talk()
- { int c, i, n, r;
- int baddies, lowers, uppers;
- int messages;
-
- D4("talk()");
- r = 0;
- ss = S_INIT;
- D4("State %d=%s",ss,gestate());
- lockwait(); /* Try to avoid collisions */
- if (device) target = device;
- /*
- ** We have a long list of initialization strings here.
- ** This has come in handy in a few cases, but usually
- ** they are mostly null.
- */
- if (m_init ) Awrite(m_init);
- if (m_init1) {Awrite(m_init1); sleep(SLEEP1);}
- if (m_init2) {Awrite(m_init2); sleep(SLEEP2);}
- if (m_init3) {Awrite(m_init3); sleep(SLEEP3);}
- ss = S_INIT;
- D4("State %d=%s",ss,gestate());
- if (m_login) Awrite(m_login);
- ss = S_LOGIN;
- D4("State %d=%s",ss,gestate());
- Response;
- nudge: /* Try to elicit a response */
- D3("Nudge.");
- if (++nudges > Nudges) {
- E("Too many nudges.");
- r = 1;
- Dead;
- }
- lockwait(); /* Try to avoid interference */
- Resync;
- if (m_nudge) /* Is a nudge message defined? */
- Awrite(m_nudge); /* If so, send it */
- idle: /* We will now accept anything */
- D3("Idle.");
- ss = S_IDLE; /* Note we're awaiting a response */
- D4("State %d=%s",ss,gestate());
- messages = 0; /* Counter to trigger nudges */
- response: /* Read a response */
- D4("Response: state=%d=%s",ss,gestate());
- if (debug > 0 && target != oldtarg) {
- if (debug >= 3) P("%s Talking to %s.",getime(),target);
- oldtarg = target;
- }
- /*
- ** Check for any of a list of known debugger prompts.
- ** If we don't get one of then, try to nudge the debugger,
- ** and try again, giving up after some number of tries.
- */
- errno = 0;
- D4("talk:l_tries=%d",l_tries);
- sleep(1); /* Sheer laziness */
- lockwait();
- if (ss != S_PASSWD) /* If not expecting password, do echoing if requested */
- echoing = echofl;
- while ((n = Pread(eol0,rsp,rspmax)) <= 0) {
- D3("No response.");
- /*
- ** Note this program loops forever waiting for something to come down the line.
- ** You might want to do something else here if there's no input.
- */
- }
- D4("talk:Pread()=%d",n);
- rsp[n] = 0;
- ++messages;
- if (debug) {
- dbgtimep = getime();
- if (debug >= 2) Ascdnm(rsp,n,"Got:");
- if (debug >= 4) Hexdnm(rsp,n,"Got:");
- }
- /*
- ** Next, we do some preliminary checking for sanity of the input.
- ** Since this program's duty is to do login interviews, the only
- ** input we really want is something that might be a login id or
- ** a password. Another likely input is a nudge from a counterpart
- ** on the other end, to which we respond with a prompt.
- */
- if (n < 3) { /* Just "\r", "\n", or "\r\n" is a nudge */
- D4("Short response, %d chars.",n);
- switch (c = rsp[0]) {
- case 0x03: /* ^C = ETX (usually means "die") */
- if (debug) P("%s: ^C in input, quitting.",getime());
- die(c);
- case '\n': /* ^J = LF */
- case '\r': /* ^M = CR */
- case 0x04: /* ^D = EOT */
- case 0x02: /* ^B = STX */
- case 0x01: /* ^A = SOH */
- ss = S_IDLE; /* Flush garbage from buffer */
- D4("State %d=%s",ss,gestate());
- lockwait();
- if (ibfa < ibfz) { /* Is there input waiting? */
- D3("Nudge plus garbage received, ignored.");
- Resync; /* Flush garbage from buffer */
- } else { /* No input waiting */
- D3("Nudged; send login prompt \"%s\"",m_login);
- Awrite(m_login); /* Send them a login prompt */
- ss = S_LOGIN; /* Note that we did it */
- D4("State %d=%s",ss,gestate());
- messages = 0;
- }
- Response; /* See if there's a response */
- case 0x10: /* This is a uucp Start-of-message */
- D3("We seem to be talking to a UUCP demon.");
- makeraw(dev); /* Paranoia! */
- Awrite("OOOOOOOO\r"); /* Try to get it to stop */
- Resync; /* Discard the rest of the message */
- if (m_init) Awrite(m_init);
- ss = S_INIT; /* Try to get back to idle state */
- D4("State %d=%s",ss,gestate());
- Response;
- }
- }
- baddies = lowers = uppers = 0;/* These are for counting letters */
- D4("Scan id for char classes...");
- for (i=0; i<n; i++) { /* Examine the response for nasty stuff */
- c = rsp[i]; /* One byte at a time */
- if (islower(c)) {
- ++lowers; /* Lower-case letters are desirable */
- D6("c=%02X-'%c' lowers=%d",c,dsp(c),lowers);
- } else
- if (isupper(c)) {
- ++uppers; /* Upper-case letters are acceptable */
- D6("c=%02X-'%c' uppers=%d",c,dsp(c),uppers);
- } else /* Everything else is dubious */
- switch (c) {
- case 0x03: /* Special goody to let others kill us */
- case 0x02:
- case 0x01:
- if (debug) P("%s: %02X in input, quitting [id]",getime(),c);
- die(c);
- case '#': /* These are likely shell prompts */
- case '$': /* Default Bourne shell prompt */
- case '%': /* Default C- shell prompt */
- case '>': /* Popular prompt in some circles */
- if (i >= n-2) { /* Likely only if at end of input */
- shprompt(rsp); /* Can we handle it? */
- Response;
- } /* If earlier in string, reject it */
- case 0x00:
- case 0x04: case 0x05: case 0x06: case 0x07:
- case 0x08: case 0x09: case 0x0B:
- case 0x0C: case 0x0E: case 0x0F:
- case 0x10: case 0x11: case 0x12: case 0x13:
- case 0x14: case 0x15: case 0x16: case 0x17:
- case 0x18: case 0x19: case 0x1A: case 0x1B:
- case 0x1C: case 0x1D: case 0x1E: case 0x1F:
- case ' ' : case ':' : /* None of these are acceptable in ids or passwords */
- D3("Invalid char %02x='%c' in input.",c,dsp(c));
- ++baddies;
- break;
- }
- }
- if (baddies || ((lowers+uppers) == 0)) { /* Is it acceptable? */
- D4("Unacceptable; baddies=%d lowers=%d uppers=%d.",baddies,lowers,uppers);
- Resync; /* No; drop buffered input */
- lockwait();
- if (baddies && messages > THRESH) {
- makeraw(dev); /* Others may have munged the driver */
- if (m_init) {
- Awrite(m_init);
- ss = S_INIT;
- D4("State %d=%s",ss,gestate());
- } else {
- Awrite(m_login);
- ss = S_LOGIN;
- D4("State %d=%s",ss,gestate());
- }
- messages = 0;
- }
- ss = S_IDLE;
- D4("State %d=%s",ss,gestate());
- Response;
- }
- switch (ss) { /* Special actions depending on state */
- case S_EXIT: /* We are trying to exit */
- if (m_exit) { /* Is there an exit command? */
- Awrite(m_exit); /* If so, send it */
- ss = S_EXIT; /* Note again that we're trying to quit */
- D4("State %d=%s",ss,gestate());
- }
- Response;
- case S_IDLE: /* We're waiting for the other end to act */
- D4("Got id while idle.");
- c = rsp[0]; /* First char of response is sometimes special */
- goto maybeid;
- case S_LOGIN: /* We just sent a login prompt */
- D4("Got response to login prompt.");
- maybeid: /* We may have a login id */
- D4("Got possible login id.");
- if (lowers == 0) { /* No lower-case letters; it's not an id */
- lockwait(); /* Make sure we're not interfering */
- makeraw(dev); /* Paranoia! */
- if (m_init) { /* Do we have a special init string? */
- Awrite(m_init);
- ss = S_INIT;
- D4("State %d=%s",ss,gestate());
- }
- Response; /* Go wait for next input */
- }
- i = checkid(rsp); /* Put it through final tests */
- if (i <= 0) { /* If it fails... */
- if (debug) {
- dbgtimep = getime();
- if (debug >= 2) Ascdnm(rsp,n,"Bad id:");
- if (debug >= 4) Hexdnm(rsp,n,"Bad id:");
- }
- Resync; /* Get port into known state */
- sleep(5); /* Extra delay for safety's sake */
- ss = S_IDLE;
- D4("State %d=%s",ss,gestate());
- Response; /* Go wait for next input */
- }
- /* It sure looks like an id */
- D3("Send password prompt \"%s\"",m_passwd);
- echoing = 0;
- Awrite(m_passwd);
- ss = S_PASSWD;
- D4("State %d=%s",ss,gestate());
- Response;
- case S_PASSWD: /* We just sent a password prompt */
- D4("Got response to password prompt.");
- i = pswd(rsp); /* Check it out to see if it's a good guy */
- if (i <= 0) { /* Successful call won't return */
- D3("Unacceptable password \"%s\"",rsp);
- Response;
- }
- E("pswd(\"%s\")=%d Shouldn't happen.",rsp,i);
- Response;
- default:
- D4("ss=%d not special",ss);
- }
- if (debug) {
- dbgtimep = getime();
- if (debug >= 2) Ascdnm(rsp,n,"Ignore:");
- if (debug >= 4) Hexdnm(rsp,n,"Ignore:");
- }
- Response;
- dead: P("Giving up; %s seems to be dead.",target);
- return r;
- }
- \!Funky\!Stuff\!
- echo file: unlock.c
- cat > unlock.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Remove the lockfile.
- */
- unlock()
- {
- D2("%s: Delete lockfile %d=\"%s\".",getime(),lockfn,lockfile);
- unlink(lockfile);
- D4("Close lockfn=%d.",lockfn);
- close(lockfn);
- lockfn = -1;
- locked = 0;
- }
- \!Funky\!Stuff\!
-
-
-